Anyone who preformed Dynamics AX application
installation or upgrade has to be familiar with standard checklists.
Normally, a checklist is a list of menu items displayed in logical
sequence. Each item represents either mandatory or optional actions to
be executed by the user in order to complete the whole procedure. In
custom Dynamics AX implementations, checklists can be used as a
convenient way to configure non standard settings. Checklists can also
be implemented as a part of third-party modules for their initial setup.
In this recipe, we will
create a checklist for user-friendly ledger budget setup. The checklist
will consists of two mandatory and one optional item.
How to do it...
1. Open AOT, and create a new class called SysCheckListInterfaceBudget:
interface SysCheckListInterfaceBudget
extends SysCheckListInterface
{
}
2. Create three more classes— one for each checklist item, with the following code:
class SysCheckListItem_BudgetModel
extends SysCheckListItem
implements SysCheckListInterfaceBudget
{
}
public str getCheckListGroup()
{
return "Setup";
}
public str getHelpLink()
{
#define.TopicId('AxShared.chm::/html/' +
'84030522-0057-412C-BFC7-DBEB4D40E5A1.htm')
;
return SysCheckListItem::sharedGuide(#TopicId);
}
public MenuItemName getMenuItemName()
{
return menuitemdisplaystr(BudgetModel);
}
public MenuItemType getMenuItemType()
{
return MenuItemType::Display;
}
str label()
{
return "Models";
}
class SysCheckListItem_BudgetRevision
extends SysCheckListItem
implements SysCheckListInterfaceBudget
{
}
public void new()
{;
super();
this.placeAfter(classnum(SysCheckListItem_BudgetModel));
this.indeterminate(true);
}
public str getCheckListGroup()
{
return "Setup";
}
public str getHelpLink()
{
#define.TopicId('AxShared.chm::/html/' +
'AACC4353-C3EB-4982-BB7F-2B36D97FF25B.htm')
;
return SysCheckListItem::sharedGuide(#TopicId);
}
public MenuItemName getMenuItemName()
{
return menuitemdisplaystr(BudgetRevision);
}
public MenuItemType getMenuItemType()
{
return MenuItemType::Display;
}
str label()
{
return "Revisions";
}
class SysCheckListItem_Budget
extends SysCheckListItem
implements SysCheckListInterfaceBudget
{
}
public void new()
{;
super();
this.addDependency(
classnum(SysCheckListItem_BudgetModel));
this.placeAfter(
classnum(SysCheckListItem_BudgetRevision));
}
public str getCheckListGroup()
{
return "Create budgets";
}
public str getHelpLink()
{
#define.TopicId('AxShared.chm::/html/' +
'6A596E1E-6803-4410-B4E4-EDE4EF44AF6D.htm')
;
return SysCheckListItem::sharedGuide(#TopicId);
}
public MenuItemName getMenuItemName()
{
return menuitemdisplaystr(LedgerBudget);
}
public MenuItemType getMenuItemType()
{
return MenuItemType::Display;
}
str label()
{
return "Budgets";
}
3. Create another class for the checklist itself:
class SysCheckList_Budget extends SysCheckList
{
container log;
}
protected str getCheckListCaption()
{
return "Budget checklist";
}
protected str getHtmlHeader()
{
return "Budget checklist";
}
protected classId getInterfaceId()
{
return classnum(SysCheckListInterfaceBudget);
}
public void save(
identifiername _name,
ClassDescription _description)
{;
if (!confind(log, _name))
{
log = conins(log, conlen(log)+1, _name);
}
checklistschecklistsbuilding}
public boolean find(
identifiername _name,
ClassDescription _description)
{
return confind(log, _name) ? true : false;
}
static void main(Args _args)
{;
SysCheckList::runCheckListSpecific(
classnum(SysCheckList_Budget),
true);
}
4. Open the SysCheckList class in AOT, and replace its checkListItemsHook() and checkListsHook() with the following code:
protected static container checkListsHook()
{
return [classnum(SysCheckList_Budget)];
}
protected static container checkListItemsHook()
{
return [classnum(SysCheckListItem_Budget),
classnum(SysCheckListItem_BudgetRevision),
classnum(SysCheckListItem_BudgetModel)];
}
5. Open the BudgetModel form in AOT, and override its close() with the following code:
public void close()
checklistschecklistsbuilding{;
super();
SysCheckList::finished(
classnum(SysCheckListItem_BudgetModel));
}
6. Open the BudgetRevision form in AOT, and override its close() with the following code:
public void close()
{;
super();
SysCheckList::finished(
classnum(SysCheckListItem_BudgetRevision));
}
7. Open the LedgerBudget form in AOT, and override its close() with the following code:
public void close()
{;
super();
SysCheckList::finished(classnum(SysCheckListItem_Budget));
}
8. Create a new Display menu item SysCheckList_Budget with the following properties:
Property
|
Value
|
---|
Name
|
SysCheckList_Budget
|
Label
|
Budget checklist
|
ObjectType
|
Class
|
Object
|
SysCheckList_Budget
|
9. To test the checklist, run the SysCheckList_Budget menu item from AOT. The following should appear on the right-hand side of the Dynamics AX window:
10.
Click on the listed items to start and complete relevant actions.
Notice how the status icons change upon completion of each task.
How it works...
The main
principle behind checklists is that we have to create a main class,
which represents the checklist itself and a number of SysCheckListItem
item classes, which act as list items. The relation between the main
class and the items is made by the use of an interface, that is, each
list item implements it, and the main class holds the reference to it.
In this example, we create an interface SysCheckListInterfaceBudget and specify it in the getInterfaceId() of the main checklist class SysCheckList_Budget. Next, we implement the interface in three SysCheckListItem classes, which correspond to Models, Revisions, and Budgets items in the checklist.
Each SysCheckListItem class contains a set of inherited methods, which allows us to define a number of different parameters for individual items:
All initialization code can be added to the new() methods. In this example, we use placeAfter() to determine the position of the item in the list relative to other items, indeterminate() to make item optional and addDependency() to make an item inactive until another specified item is completed.
getCheckListGroup() defines item dependency to a specific group. The Budget checklist has two groups, Setup and Create budgets.
getHelpLink() is responsible for placing the relevant help link in the form of a question mark next to the item.
getMenuItemName() and getMenuItemType() contain a name and a type of menu item, which is executed upon user request. Here, we have Budget model, Budget revisions, and Ledger budget forms respectively in each class.
And finally custom labels can be set in label().
Once the items are ready, we create the main checklist class SysCheckList_Budget, which extends the standard SysCheckList. We override some of the methods to add custom functionality to the checklist:
getCheckListCaption() sets the title of the checklist.
getHtmlHeader() could be used to add some descriptive text.
As mentioned before, getInterfaceId() is the place where we specify the name of the checklist item interface.
The methods save() and find()
are used to store and retrieve respectively the status of each item in
the list. In this example, we store statuses in the local variable log to make sure that statuses are reset every time we run the checklist.
The static method main() runs the class. Here, we use runCheckListSpecific() of the system SysCheckList class to start the checklist.
The display menu item we created is pointing to the checklist class and may be used to add the checklist to a user menu.
When building checklists, it is necessary to add them and their items to the global checklist and checklist item list. the SysCheckList class contains two methods— checkLists() and checkListItems()— where all system checklists and their items are registered. The same class provides two more methods— checkListsHook() and checkListItemsHook()—
where custom checklists should be added. As a part of this example, we
also add our budget checklist and its items to the SysCheckList.
Final modifications have to be done in all checklist forms. We call the finished() of the SysCheckList class in the close()
of each form to update the status of the corresponding checklist item.
In other words, it means that item status will be set as completed when
the user closes the form. This code does not affect the normal use of
the form when it is opened from the regular menu. Of course, more logic
could be added here if the completion of a specific item is not that
straightforward.
Also notice that the system automatically adds a link called Information, which describes the checklist statuses:
There's more...
The checklist in this
example stores item statuses per each run. This means that every time
you close the checklist, its statuses are lost and are set to their
initial states upon checklist start. By replacing save() and find() in SysCheckList_Budget with the following code, we can store statuses permanently in the SysSetupLog table:
public boolean find(
identifiername _name,
ClassDescription _description)
{
return SysSetupLog::find(_name, _description).RecId != 0;
}
public void save(
identifiername _name,
ClassDescription _description)
{;
SysSetupLog::save(_name, _description);
}
In this case, every time the checklist starts, the system will pick up its last status from the SysSetupLog table and allow the user to continue the checklist.